#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <amqp.h>
#include <amqp_tcp_socket.h>

int main() {
    amqp_connection_state_t conn;
    amqp_socket_t *socket;
    amqp_bytes_t queuename;
    
    // 建立连接
    conn = amqp_new_connection();
    socket = amqp_tcp_socket_new(conn);
    
    if (amqp_socket_open(socket, "localhost", 5672) != AMQP_STATUS_OK) {
        fprintf(stderr, "Failed to open socket\n");
        return 1;
    }
    
    // 登录
    if (amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, 
                   "guest", "guest").reply_type != AMQP_RESPONSE_NORMAL) {
        fprintf(stderr, "Failed to login\n");
        return 1;
    }
    
    // 打开通道
    amqp_channel_open(conn, 1);
    if (amqp_get_rpc_reply(conn).reply_type != AMQP_RESPONSE_NORMAL) {
        fprintf(stderr, "Failed to open channel\n");
        return 1;
    }
    
    // 声明 exchange
    amqp_exchange_declare(conn, 1, amqp_cstring_bytes("test_exchange"),
                         amqp_cstring_bytes("direct"), 0, 1, 0, 0,
                         amqp_empty_table);
    if (amqp_get_rpc_reply(conn).reply_type != AMQP_RESPONSE_NORMAL) {
        fprintf(stderr, "Failed to declare exchange\n");
        return 1;
    }
    
    // 声明队列
    // 当使用 amqp_empty_bytes 作为队列名时：RabbitMQ 会生成一个唯一的队列名，通常是类似 amq.gen-xxxxx 的格式 这种队列被称为 临时队列 或 匿名队列
    {
        amqp_queue_declare_ok_t *r = amqp_queue_declare(conn, 1,
                                                       amqp_empty_bytes, 0, 0, 0, 0,
                                                       amqp_empty_table);
        if (amqp_get_rpc_reply(conn).reply_type != AMQP_RESPONSE_NORMAL) {
            fprintf(stderr, "Failed to declare queue\n");
            return 1;
        }
        queuename = amqp_bytes_malloc_dup(r->queue);   
    }
    
    // 绑定队列到 exchange
    amqp_queue_bind(conn, 1, queuename,
                   amqp_cstring_bytes("test_exchange"),
                   amqp_cstring_bytes("test_key"),
                   amqp_empty_table);
    if (amqp_get_rpc_reply(conn).reply_type != AMQP_RESPONSE_NORMAL) {
        fprintf(stderr, "Failed to bind queue\n");
        return 1;
    }
    
    // 开始消费
    amqp_basic_consume(conn, 1, queuename, amqp_empty_bytes, 0, 1, 0, amqp_empty_table);
    if (amqp_get_rpc_reply(conn).reply_type != AMQP_RESPONSE_NORMAL) {
        fprintf(stderr, "Failed to start consuming\n");
        return 1;
    }
    
    printf("Waiting for messages...\n");
    
    // 消费消息
    for (;;) {
        amqp_rpc_reply_t res;
        amqp_envelope_t envelope;
        
        amqp_maybe_release_buffers(conn);
        res = amqp_consume_message(conn, &envelope, NULL, 0);
        
        if (AMQP_RESPONSE_NORMAL != res.reply_type) {
            break;
        }
        
        printf("Received message: %.*s\n", 
               (int)envelope.message.body.len, 
               (char *)envelope.message.body.bytes);
        
        amqp_destroy_envelope(&envelope);
    }
    
    // 清理
    amqp_bytes_free(queuename);
    amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
    amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
    amqp_destroy_connection(conn);
    
    return 0;
}